#![allow(non_snake_case)]
use icondata as i;
use leptos::prelude::*;
use leptos_icons::*;
use shq_common::prelude::Size;
use thaw_utils::{class_list, BoxOneCallback, Model};
use crate::select::tree_items::TreeState;
use super::tree_items::{CheckState, ExpandMode, TreeItems};
#[component]
pub fn MultiTreeSelect(
    ///值列表
    #[prop(optional, into)]
    values: Model<Vec<String>>,
    ///选项
    #[prop(into)]
    tree_items: StoredValue<TreeItems>,
    ///初始展开模式
    #[prop(default=ExpandMode::First, into)]
    init_expand_mode: ExpandMode,
    ///值改变回调
    #[prop(optional, into)]
    on_change: Option<BoxOneCallback<Vec<String>>>,
    ///确认回调
    #[prop(optional, into)]
    on_confirm: Option<BoxOneCallback<Vec<String>>>,
    ///取消回调
    #[prop(optional, into)]
    on_cancel: Option<BoxOneCallback<()>>,
    ///是否只选择叶子节点
    #[prop(optional, into)]
    only_select_leaf: MaybeProp<bool>,
    ///是否可以过滤选项
    #[prop(optional, into)]
    can_filter: MaybeProp<bool>,
    ///选中项是否只读
    #[prop(optional, into)]
    checked_item_read_only: MaybeProp<bool>,
    ///控件大小
    #[prop(optional, into)]
    size: MaybeProp<Size>,
    #[prop(optional)] inner_max_width: u32,
    #[prop(optional)] height: u32,
    // 确认，取消按钮是否显示
    #[prop(default=true.into(),optional, into)] show_confirm_cancel_btn: MaybeProp<bool>,
) -> impl IntoView {
    let tree_state = StoredValue::new(
        tree_items.with_value(|tis| values.with_untracked(|vals|TreeState::from_multi(tis, &vals, &init_expand_mode))),
    );
    let filter_text: RwSignal<Option<String>> = RwSignal::new(None);
    let style_width = if inner_max_width > 0 {
        format!("max-width:{}px", inner_max_width)
    } else {
        "".to_owned()
    };
    Effect::new(move || {
        let values = tree_state.with_value(|tis| tis.get_selected_values());
        on_change.as_ref().map(|cb| cb(values));
    });
    let root_ids =
        move || filter_text.with(|v| tree_state.with_value(|tis| tis.get_root_ids(v.as_deref())));
    let title_view = move || {
        if can_filter.get().unwrap_or_default() {
            Some(view! {
                <label class=class_list!["input input-bordered flex items-center gap-2 mx-2 mt-2",size.get().unwrap_or_default().to_class("input")]>
                    <input type="text" class="grow"  style=style_width
                    placeholder="筛选" on:input=move |ev| {
                        let val = event_target_value(&ev).trim().to_string();
                        if val.is_empty() {
                            filter_text.update(|v|*v=None);
                        }else{
                            filter_text.update(|v|*v=Some(val));
                        }
                    }/>
                    <Icon icon=i::AiSearchOutlined/>
                </label>
            })
        } else {
            None
        }
    };
    view! {
        <div class="flex flex-col w-full overflow-hidden" style=("max-height", move || if height==0 {"100%".to_string()} else {format!("{}px", height)})>
            {title_view()}
            <div class="flew-1 overflow-auto">
                <ul class="menu bg-base-100 rounded-box">
                    {
                        move || root_ids().into_iter().map(|id|{
                            // let icon = icon_map.get(&id).flatten().cloned();
                            render_tree_node(tree_state, &id, filter_text, only_select_leaf, None, checked_item_read_only, size)
                        }).collect_view()
                    }
                </ul>
            </div>
            <div class="flex flex-row gap-2 justify-center p-2"
                 style=("display", move||if show_confirm_cancel_btn.get().unwrap_or_default() {""} else {"none"})>
                <button class="btn btn-primary btn-sm"
                    on:click=move |e|{
                        e.stop_propagation();
                        let values = tree_state.with_value(|tis| tis.get_selected_values());
                        on_confirm.as_ref().map(|cb| cb(values));
                    }
                >
                    { "确定" }
                </button>
                <button class="btn btn-secondary btn-sm"
                    on:click=move |e|{
                        e.stop_propagation();
                        on_cancel.as_ref().map(|cb| cb(()));
                    }
                >
                    { "取消" }
                </button>
            </div>
        </div>
    }
}
#[component]
fn LeafTreeNode(
    tree_state: StoredValue<TreeState>,
    item_id: String,
    label: String,
    checked_state_signal: RwSignal<CheckState>,
    icon: Option<i::Icon>,
    read_only: MaybeProp<bool>,
) -> impl IntoView {
    let icon_view = icon.as_ref().map(|i| {
        view! {
            <Icon icon=*i/>
        }
    });
    let is_active = false;
    let checked = move || {
        let checked_state = checked_state_signal.get();
        checked_state == CheckState::All
    };
    view! {
        <li>
            <span class=("bg-base-300",is_active)>
                <input type="checkbox"
                    prop:checked=checked
                    class="checkbox checkbox-sm z-10"
                    disabled=move|| read_only.get().unwrap_or_default()&&checked()
                    on:input=move |e|{
                        e.stop_propagation();
                        let checked = event_target_checked(&e);
                        tree_state.with_value(|tis| {
                            tis.set_multi_selected(&item_id, checked);
                        });
                    }/>
                <a on:click=move |e|{
                    e.stop_propagation();
                    checked_state_signal.set(if checked() {CheckState::All} else {CheckState::None});
                }>
                    <span class="flex items-center gap-2">
                        {label}
                        {icon_view}
                    </span>
                </a>
            </span>
        </li>
    }
}
#[component]
fn BranchTreeNode(
    tree_state: StoredValue<TreeState>,
    item_id: String,
    child_ids: Vec<String>,
    label: String,
    filter_text: RwSignal<Option<String>>,
    checked_state_signal: RwSignal<CheckState>,
    expanded_signal: RwSignal<bool>,
    only_select_leaf: MaybeProp<bool>,
    icon: Option<i::Icon>,
    read_only: MaybeProp<bool>,
    size: MaybeProp<Size>,
) -> impl IntoView {
    let item_id_store = StoredValue::new(item_id);
    let check_view = move || {
        let item_id = item_id_store.get_value();
        let checked = move || {
            let checked_state = checked_state_signal.get();
            checked_state == CheckState::All || checked_state == CheckState::Any
        };
        if only_select_leaf.get().unwrap_or_default() {
            return None;
        }
        Some(view! {
            <input type="checkbox" prop:checked=checked
                class=class_list!["checkbox",size.get().unwrap_or_default().to_class("checkbox")]
                class=("checkbox-success",checked_state_signal.get()==CheckState::All)
                class=("checkbox-warning",checked_state_signal.get()==CheckState::Any)
                disabled=move||read_only.get().unwrap_or_default()&&checked()
                on:click=move |e|{
                    e.stop_propagation();
                }
                on:input=move |e|{
                    e.stop_propagation();
                    let checked = event_target_checked(&e);
                    tree_state.with_value(|tis| {
                        tis.set_multi_selected(&item_id, checked);
                    });
                }
            />
        })
    };
    let is_expanded_value = move || expanded_signal.get();
    view! {
        <li>
            <span class="menu-dropdown-toggle"
                class=("menu-dropdown-show", is_expanded_value)
                on:click=move |e|{
                    e.stop_propagation();
                    expanded_signal.update(|v| *v = !*v);
                }
            >
                {check_view}
                {label}
            </span>
            <ul class="menu-dropdown"
                class=("menu-dropdown-show", is_expanded_value)
            >
                {
                    child_ids.into_iter().map(|id|{
                        render_tree_node(tree_state, &id, filter_text, only_select_leaf, icon, read_only, size)
                    }).collect_view()
                }
            </ul>
        </li>
    }
}

fn render_tree_node(
    tree_state: StoredValue<TreeState>,
    item_id: &str,
    filter_text: RwSignal<Option<String>>,
    only_select_leaf: MaybeProp<bool>,
    icon: Option<i::Icon>,
    read_only: MaybeProp<bool>,
    size: MaybeProp<Size>,
) -> impl IntoView {
    let checked_state_signal = tree_state
        .with_value(|ts| ts.get_multi_selected(item_id))
        .unwrap_or_default();
    let expanded_signal = tree_state
        .with_value(|ts| ts.get_expanded(item_id))
        .unwrap_or_default();
    let item_id_store = StoredValue::new(item_id.to_owned());
    let child_ids = {
        filter_text.with_untracked(|f| {
            tree_state.with_value(|tis| {
                let item_id = item_id_store.get_value();
                tis.get_item_ids_by_pid(&item_id, f.as_deref())
            })
        })
    };
    let label = tree_state.with_value(|tis| tis.get_label(&item_id).to_owned());
    let is_leaf = tree_state.with_value(|tis| tis.is_leaf(&item_id));
    if is_leaf {
        let item_id = item_id.to_owned();
        Some(
            view! {
                <LeafTreeNode tree_state item_id label checked_state_signal icon read_only/>
            }
            .into_any(),
        )
    } else {
        if child_ids.iter().count() == 0 {
            None
        } else {
            Some(
                view!{
                    <BranchTreeNode
                        tree_state item_id=item_id.to_owned() child_ids label filter_text checked_state_signal expanded_signal icon only_select_leaf read_only size
                    />
                }.into_any()
            )
        }
    }
}
